//
//  stats_server_processor.cpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2013-2014 Razvan Coca (razvan dot coca at  gmail dot com)
// This is mostly generated code. Generator is distributed under GPL. Edit it to suit your needs.
// 


#include <boost/logic/tribool.hpp>
#include "components/protocol/stats_server_processor.hpp"
#include "logging/logging.hpp"

namespace components
{
namespace protocol
{

stats_server_processor::stats_server_processor(boost::asio::io_service &ios, std::string const& persist_path,
                                               boost::posix_time::minutes lifetime,std::string cluster, std::string node):
    stats_container_(ios,persist_path,lifetime),current_state_(start),cluster_(cluster),node_(node)
{

}
void replace_with_error(stats_message_t& msg,std::string const& error_message)
{
    stats_val v;
    v.set_value_type(stats_val::err);
    v.set_err_st(error_message);
    stats_data s;
    s.mutable_value()->CopyFrom(v);
    s.set_name("error");
    s.set_timestamp(time(nullptr));
    msg.mutable_data()->CopyFrom(s);
}
void stats_server_processor::init_trans(stats_message_t& msg)
{
    trans_id_=msg.trans().trans_id();
    seq_no_=msg.trans().seq_no();
}
void stats_server_processor::update_trans(stats_message_t& msg)
{
    trans_label t;
    t.set_trans_id(trans_id_);
    t.set_seq_no(++seq_no_);
    msg.mutable_trans()->CopyFrom(t);
}

void stats_server_processor::update_source(stats_message_t& msg)
{
    node_id n;
    n.set_cluster(cluster_);
    n.set_node(node_);
    msg.mutable_source()->CopyFrom(n);
}
void stats_server_processor::reset_pending_replies()
{
    pending_replies_.clear();
    current_replies_=pending_replies_.begin();
}

boost::logic::tribool stats_server_processor::process_request_set(stats_message_t& msg,udp_endpoint_t& peer,boost::system::error_code const &ec)
{
    auto event=msg.type();
    std::string mkey=message_key(msg);
    if(current_state_!=start) {
        DLOG(INFO)<<__FUNCTION__<<" -> indeterminate";
        return boost::indeterminate;
    }

    if(event!=stats_message_t::request_set) {
        DLOG(INFO)<<__FUNCTION__<<" -> indeterminate";
        return boost::indeterminate;
    }

    msg.set_type(stats_message_t::end);

    if(!stats_container_.add(msg))
    {
        DLOG(INFO)<<__FUNCTION__<<" -> false";
        update_trans(msg);
        update_source(msg);
        return false;
    }


    current_state_=reply;
    pending_replies_.clear();
    init_trans(msg);
    update_trans(msg);
    pending_replies_.push_back(msg);
    current_replies_=pending_replies_.begin();

    DLOG(INFO)<<__FUNCTION__<<" -> true";
    return true;
}

boost::logic::tribool stats_server_processor::process_request_get(stats_message_t& msg,udp_endpoint_t& peer,boost::system::error_code const &ec)
{
    auto event=msg.type();

    if(current_state_!=start) {
        DLOG(INFO)<<__FUNCTION__<<" -> indeterminate";
        return boost::indeterminate;
    }
    if(event!=stats_message_t::request_get) {
        DLOG(INFO)<<__FUNCTION__<<" -> indeterminate";
        return boost::indeterminate;
    }
    auto mkey=message_key(msg);
    pending_replies_.clear();

    init_trans(msg);
    update_trans(msg);

    if(!stats_container_.get(mkey,pending_replies_))     {
        DLOG(INFO)<<__FUNCTION__<<" -> false";
        update_source(msg);
        return false;
    }

    current_state_=reply;

    if(current_replies_==pending_replies_.end())
    {
        msg.set_type(stats_message_t::end);
        replace_with_error(msg,"key not found");
        reset_pending_replies();
        DLOG(INFO)<<__FUNCTION__<<" -> true";
        return true;
    }
    else
    {
        for(auto& m:pending_replies_)
        {
            m.set_type(stats_message_t::reply);
        }
        pending_replies_.back().set_type(stats_message_t::end);
        current_replies_=pending_replies_.begin();
    }

    DLOG(INFO)<<__FUNCTION__<<" -> true";
    return true;
}
boost::logic::tribool stats_server_processor::process_do_reply(stats_message_t& msg,udp_endpoint_t& peer,boost::system::error_code const &ec)
{
    stats_message_t::_type event;
    if(current_replies_!=pending_replies_.end())
        event=current_replies_->type();
    else event=stats_message_t::end;
    if(current_state_!=reply)
    {
        DLOG(INFO)<<__FUNCTION__<<" -> indeterminate";
        return boost::indeterminate;
    }
    if(event!=stats_message_t::reply)
    {
        DLOG(INFO)<<__FUNCTION__<<" -> indeterminate";
        return boost::indeterminate;
    }
    msg=*current_replies_;
    msg.set_type(stats_message_t::reply);
    ++current_replies_;
    if(current_replies_==pending_replies_.end())
    {
        DLOG(INFO)<<__FUNCTION__<<" last of replies";
        msg.set_type(stats_message_t::end);
        reset_pending_replies();
        current_state_=reply;
    }
    update_trans(msg);
    DLOG(INFO)<<__FUNCTION__<<" -> true";
    return true;
}
boost::logic::tribool stats_server_processor::process_end(stats_message_t& msg,udp_endpoint_t& peer,boost::system::error_code const &ec)
{
    stats_message_t::_type event;
    if(current_replies_!=pending_replies_.end())
        event=current_replies_->type();
    else event=stats_message_t::end;

    update_trans(msg);
    if(!msg.has_source())update_source(msg);
    if(!msg.has_data())
    {
        msg.set_type(event);
        replace_with_error(msg,":Protocol error:");
    }
    if(current_state_!=reply) {
        DLOG(INFO)<<__FUNCTION__<<" -> indeterminate";
        return boost::indeterminate;
    }
    if(event!=stats_message_t::end) {
        DLOG(INFO)<<__FUNCTION__<<" -> indeterminate";
        return boost::indeterminate;
    }
    current_state_=start;
    msg=*current_replies_;
    msg.set_type(event);
    update_trans(msg);
    if(!msg.has_source())update_source(msg);
    reset_pending_replies();
    DLOG(INFO)<<__FUNCTION__<<" -> false";
    return false;
}


}//namespace protocol
}//namespace components
